#!/bin/bash

# This is a wrapper script for detect-secrets.
# Run this script from the root of the repository without any arguments to see usage.
#   - i.e. ./git_hooks/secrets/run-detect-secrets
# This script is used by the pre-commit hook in git_hooks/hooks/pre-commit.

color_highlight='\033[1;95m'
color_none='\033[0m'

# if this script is not run from the root of the repository, exit
if [ ! -f "./git_hooks/secrets/run-detect-secrets" ]; then
    echo >&2 "This script must be run from the root of the repository."
    exit 1
fi

command=$1
# if no arguments provided or if help is the command, print usage
if [ $# -eq 0 ] || [ "$command" = "help" ]; then
    echo -e "Usage: run-detect-secrets ${color_highlight}[command]${color_none}"
    echo -e "Commands:"
    echo -e "  ${color_highlight}init-baseline${color_none}: create a baseline file with all secrets in the repo"
    echo -e "  ${color_highlight}audit-baseline${color_none}: audit the baseline file to mark false positives"
    echo -e "  ${color_highlight}update-baseline${color_none}: update the baseline file with all secrets in the repo"
    echo -e "  ${color_highlight}generate-report${color_none}: generate a JSON report of all secrets in the repo"
    echo -e "  ${color_highlight}run-hook${color_none}: run the detect-secrets-hook on staged files"
    echo -e "  ${color_highlight}run-hook-all${color_none}: run detect-secrets-hook on all files in the repo"
    echo -e "  ${color_highlight}help${color_none}: print this help message"
    exit 0
fi

# check that detect-secrets is installed
if ! command -v detect-secrets &> /dev/null
then
    echo >&2 "detect-secrets is not installed. Install detect-secrets with 'pip install detect-secrets' or 'brew install detect-secrets'."
    exit 1
fi

add-safe-directory () {

    pwd="$(pwd)"
    while IFS= read -r line; do
        if [ "${line}" = "*" ] || [ "${line}" = "${pwd}" ]; then
            return 0
        fi
    done < <(git config --global --get-all safe.directory)

    git config --global --add safe.directory "${pwd}"

}

add-safe-directory

baseline_file="git_hooks/secrets/.secrets.baseline"
baseline_file_pattern="${baseline_file}.*"
# Use the pro baseline file if the repo is rstudio-pro
if git remote -v | grep -q rstudio-pro; then
    is_pro=true
    baseline_file="${baseline_file}_pro"
fi

check_baseline_file_exists() {
    if [ ! -f "$baseline_file" ]; then
        echo >&2 "Baseline file ${baseline_file} does not exist. Run 'run-detect-secrets init-baseline' to create it."
        exit 1
    fi
}

# --no-verify is used to skip additional secret verification via a network call
# If it is specified for creating the baseline file, it should also be specified for updating the baseline file
no_verify="--no-verify"

# Exclude external files (third-party libraries, etc.) from the baseline file
#   - https://github.com/Yelp/detect-secrets?tab=readme-ov-file#--exclude-files
# The baseline file needs to be excluded explicitly. This seems like a bug in detect-secrets since
# the default filter `detect_secrets.filters.common.is_baseline_file` should exclude the baseline file.
exclude_files=(--exclude-files ${baseline_file_pattern} --exclude-files '.*/.*.min.js' --exclude-files 'src/cpp/ext/fmt/doc/html/api.html' --exclude-files 'src/cpp/ext/fmt/doc/html/searchindex.js' --exclude-files 'dependencies/submodules/.*')

if [ "$command" = "init-baseline" ]; then
    echo "Initializing detect-secrets baseline file ${baseline_file}"
    if [ -f "$baseline_file" ]; then
        read -p $'\tBaseline file already exists. Would you like to overwrite it? You will lose any marked false positives. (y/n): ' -r
        if [[ $REPLY =~ ^[Yy]$ ]]
        then
            echo -e "\tOverwriting existing baseline file."
        else
            echo -e "\tNot overwriting existing baseline file."
            exit 0
        fi
    fi
    echo -e "\tSecret scanning in progress...this should take less than a minute."
    detect-secrets scan ${no_verify} "${exclude_files[@]}" > ${baseline_file}
elif [ "$command" = "audit-baseline" ]; then
    echo "Auditing detect-secrets baseline file ${baseline_file}"
    check_baseline_file_exists
    detect-secrets audit ${baseline_file}
    exit $?
elif [ "$command" = "update-baseline" ]; then
    echo "Updating detect-secrets baseline file ${baseline_file}"
    check_baseline_file_exists
    echo -e "\tSecret scanning in progress...this should take less than a minute."
    # --force-use-all-plugins ensures that new plugins are picked up and used to update the baseline file
    detect-secrets scan ${no_verify} "${exclude_files[@]}" --force-use-all-plugins --baseline ${baseline_file}
    exit $?
elif [ "$command" = "generate-report" ]; then
    report_file="./git_hooks/secrets/secrets_report"
    if [ "$is_pro" = true ]; then
        report_file="${report_file}_pro"
    fi
    report_file="${report_file}.json"
    echo "Generating detect-secrets report to ${report_file}"
    check_baseline_file_exists
    detect-secrets audit --report ${baseline_file} > ${report_file}
    exit $?
elif [ "$command" = "run-hook" ]; then
    check_baseline_file_exists
    git diff --staged --name-only -z | xargs -0 detect-secrets-hook ${no_verify} --baseline ${baseline_file} "${exclude_files[@]}"
    exit $?
elif [ "$command" = "run-hook-all" ]; then
    echo "Scanning all files in the repository for secrets"
    git ls-files -z | xargs -0 detect-secrets-hook ${no_verify} --baseline ${baseline_file} "${exclude_files[@]}"
    exit $?
else
    echo "Invalid command: ${command}. Run 'run-detect-secrets help' for a list of valid commands."
    exit 1
fi

exit 0
